<template>
  <div class="page-container">
    <el-container>
      <el-aside class="page-aside" width="280px" v-drag v-collapse>
        <div class="title">
          <div class="title-content">目录</div>
          <div class="title-button">
            <div class="button-list">
              <div class="button-item">
                <ac-icon
                  iconId="018dca412c4e207388f7"
                  :style="'cursor: pointer;color: ' + (treeCheck ? 'rgb(0,133,246)' : '#999') + ';font-size: 18px;'"
                  :title="treeCheck ? '导入模式' : '导出模式'"
                  @click.stop="treeCheck = !treeCheck"
                />
              </div>
              <div class="button-item">
                <ac-icon
                  iconId="018ece4f749ec5911772"
                  style="cursor: pointer;color: rgb(0,133,246); font-size: 18px;"
                  title="导出数据模型"
                  @click.stop="handleExport"
                />
              </div>
              <div class="button-item">
                <el-upload
                  action=""
                  :http-request="handleImport"
                  :show-file-list="false"
                  accept=".dat"
                >
                  <ac-icon
                    iconId="018ece4f70fcf0627f81"
                    style="cursor: pointer;color: rgb(0,133,246); font-size: 18px;"
                    title="导入数据模型"
                  />
                </el-upload>
              </div>
              <div class="button-item">
                <ac-icon
                  iconId="018dc9c3efed1f464d38"
                  style="cursor: pointer;color: rgb(0,133,246); font-size: 16px;"
                  title="下载数据模型配置模板"
                  @click.stop="downloadTpl"
                />
              </div>
              <div class="button-item">
                <el-upload
                  action=""
                  :http-request="handleUpload"
                  :show-file-list="false"
                  accept=".xls,.xlsx,.csv"
                >
                  <ac-icon
                    iconId="018dc9c3efd2131ecc10"
                    style="cursor: pointer;color: rgb(0,133,246); font-size: 16px;"
                    title="上传数据模型配置"
                  />
                </el-upload>
              </div>
            </div>
            <el-dropdown trigger="hover">
              <span class="title-button-box">
                <ac-icon
                  iconId="018dc9c3efed46e8b927"
                  style="cursor: pointer;font-size: 18px;"
                  @click.stop
                />
              </span>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item
                    v-for="(item, index) in plusButtons"
                    :key="index"
                    @click.stop="clickPlusItem(item.type, {})"
                    :divided="item.divider || false"
                  >
                    <ac-icon :iconId="item.iconId" :color="item.iconColor" style="margin-right: 5px" />{{item.name}}
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>
        </div>
        <div class="filter-box">
          <el-input placeholder="搜索" v-model="filterText" clearable />
        </div>
        <div class="page-aside-grow">
          <el-tree
            ref="tree"
            class="tree"
            node-key="id"
            v-loading="treeLoading"
            element-loading-text="数据加载中..."
            :data="treeData"
            :props="treeProps"
            :highlight-current="true"
            :default-expanded-keys="treeExpand"
            :expand-on-click-node="!treeCheck"
            :filter-node-method="filterNode"
            :show-checkbox="treeCheck"
            @node-click="nodeClick"
          >
            <template v-slot="{ node, data }">
              <div class="node-item">
                <span v-if="data.type === 'folder'" class="icon">
                  <ac-icon v-if="node.expanded" style="color: orange" iconId="018dc9c3efedbb59d0b3" />
                  <ac-icon v-else style="color: orange" iconId="018dc9c3efed6d208a59" />
                </span>
                <span v-else class="icon">
                  <ac-icon v-if="data.type === 'model'" iconId="018dc9c3efb74ac607cb" style="color: #0085f6" />
                </span>
                <span class="node-label" :title="data.text"><span>{{data.text}}</span></span>
                <div class="node-button">
                  <el-dropdown trigger="hover" placement="bottom-start">
                    <span class="node-button-item">
                      <ac-icon iconId="018dca6283a1e534a046" @click.stop />
                    </span>
                    <template #dropdown>
                      <el-dropdown-menu>
                        <div v-if="data.type === 'folder'">
                          <el-dropdown-item
                            v-for="(item, index) in plusButtons"
                            :key="index"
                            @click.stop="clickPlusItem(item.type, data)"
                          >
                            <ac-icon
                              :iconId="item.iconId"
                              :style="{
                                'margin-right': '5px',
                                'color': item.iconColor
                              }"
                            />
                            {{item.name}}
                          </el-dropdown-item>
                        </div>
                        <el-dropdown-item @click="updateNode(data.type, data.data)">
                          <ac-icon iconId="018dca6db20c6a3aaf68" style="color: #0085f6;margin-right: 5px" />
                          修改{{data.type === 'folder' ? '目录' : '数据模型'}}
                        </el-dropdown-item>
                        <el-dropdown-item v-if="data.type === 'model'" @click="copyNode(data.type, data.data)">
                          <ac-icon iconId="018dc9c3efb82f31c161" style="color: #67c23a;margin-right: 5px" />
                          复制数据模型
                        </el-dropdown-item>
                        <el-dropdown-item @click="moveNode(data.type, data.data)">
                          <ac-icon iconId="018dca444e0754edef13" style="color: #FF6600;margin-right: 5px" />
                          移动{{data.type === 'folder' ? '目录' : '数据模型'}}
                        </el-dropdown-item>
                        <el-dropdown-item @click="deleteNode(data.type, data.data)">
                          <ac-icon iconId="018dc9c3efd3a0502886" style="color: #F56C6C;margin-right: 5px" />
                          删除{{data.type === 'folder' ? '目录' : '数据模型'}}
                        </el-dropdown-item>
                      </el-dropdown-menu>
                    </template>
                  </el-dropdown>
                </div>
              </div>
            </template>
          </el-tree>
        </div>
      </el-aside>
      <el-main class="page-main">
        <div
          v-if="dataModelShow"
          class="fit-container"
          style="height: 100%;"
        >
          <el-form
            ref="dataModelForm"
            label-width="85px"
            :model="dataModelData"
            :rules="dataModelRules"
            style="height: 100%;display: flex;flex-direction: column;"
          >
            <el-row style="margin-top: 10px;">
              <el-col :span="6">
                <el-form-item label="模型编码" prop="code">
                  <el-input v-model="dataModelData.code" :disabled="true" placeholder="系统自动生成" />
                </el-form-item>
              </el-col>
              <el-col :span="6">
                <el-form-item label="模型名称" prop="name">
                  <el-input v-model="dataModelData.name"></el-input>
                </el-form-item>
              </el-col>
              <el-col :span="6">
                <el-form-item label="目录" prop="folderId">
                  <ac-tree
                    v-model="dataModelData.folderId"
                    dataUrl="/system/dataFolder/queryTree"
                    :leafSelect="false"
                  />
                </el-form-item>
              </el-col>
              <el-col :span="6">
                <el-form-item label="模型类型" prop="type">
                  <ac-dict-buttons
                    v-model="dataModelData.type"
                    dictCode="dictModelType"
                    @change="dataModelData.sourceId = ''"
                    :disabled="!!dataModelData.id"
                  />
                </el-form-item>
              </el-col>
              <el-col :span="6" v-if="dataModelData.type === '2'">
                <el-form-item label="视图名称" prop="sourceId">
                  <ac-remote-select
                    v-model="dataModelData.sourceId"
                    dataUrl="/system/view/queryPage"
                    :option="{id: dataModelData.sourceId, name: dataModelData.sourceName}"
                  />
                </el-form-item>
              </el-col>
              <el-col :span="6" v-if="dataModelData.type === '2'">
                <el-button
                  style="margin-left: 15px;"
                  type="success"
                  size="default"
                  :disabled="!dataModelData.sourceId"
                  :loading="viewLoading"
                  @click="loadView"
                >加载视图字段</el-button>
              </el-col>
              <el-col :span="6" v-if="dataModelData.type === '3'">
                <el-form-item label="源表名称" prop="sourceId">
                  <ac-remote-select
                    v-model="dataModelData.sourceId"
                    dataUrl="/system/table/queryPage"
                    idProp="table_name"
                    nameProp="table_name table_comment"
                    @change="changeTable"
                  />
                </el-form-item>
              </el-col>
              <el-col :span="6" v-if="dataModelData.type === '3'">
                <el-button
                  style="margin-left: 15px;"
                  type="success"
                  size="default"
                  :disabled="!dataModelData.sourceId"
                  :loading="viewLoading"
                  @click="loadTable"
                >加载源表字段</el-button>
              </el-col>
            </el-row>
            <el-tabs
              v-model="tabName"
              element-loading-text="数据加载中..."
              class="fit-tab fit-box"
            >
              <el-tab-pane label="字段管理" name="field" class="fit-box">
                <el-table
                  ref="sortTable"
                  v-loading="dataFieldLoading"
                  element-loading-text="数据加载中..."
                  :show-overflow-tooltip="false"
                  class="field-table fit-table edit-table"
                  width="100%"
                  :data="dataFieldList"
                  :border="true"
                  :stripe="false"
                  :row-key="getFieldRowKey"
                  :row-class-name="getRowClassName"
                >
                  <el-table-column
                    header-align="center"
                    label="字段名称"
                    :min-width="100"
                    prop="fieldName"
                  >
                    <template #default="scope">
                      <el-input
                        v-model="scope.row.fieldName"
                        :disabled="scope.row.builtin === '1'"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="显示名称"
                    :min-width="120"
                    prop="showName"
                  >
                    <template #default="scope">
                      <el-input
                        v-model="scope.row.showName"
                        :disabled="scope.row.builtin === '1'"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="是否主键"
                    :width="80"
                    prop="primaryKey"
                  >
                    <template #default="scope">
                      <ac-dict-switch
                        v-model="scope.row.primaryKey"
                        dictCode="dictYesNo"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="字段类型"
                    :width="110"
                    prop="fieldType"
                  >
                    <template #default="scope">
                      <ac-select
                        v-model="scope.row.fieldType"
                        options="字符,整数,小数,日期,时间,图片,视频,附件,联动,派生,大文本"
                        :disabled="scope.row.builtin === '1'"
                        @change="() => changeFieldType(scope.row)"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="字段长度"
                    :width="90"
                    prop="fieldSize"
                  >
                    <template #default="scope">
                      <ac-number
                        v-model="scope.row.fieldSize"
                        :disabled="scope.row.builtin === '1'
                          || '整数,时间,图片,视频,附件,联动,派生,大文本'.indexOf(scope.row.fieldType) >= 0"
                        :point="0"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="字段精度"
                    :width="80"
                    prop="fieldPrecision"
                  >
                    <template #default="scope">
                      <ac-number
                        v-model="scope.row.fieldPrecision"
                        :disabled="scope.row.builtin === '1' || scope.row.fieldType !== '小数'"
                        :point="0"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="文本框类型"
                    :width="120"
                  >
                    <template #default="scope">
                      <ac-select
                        v-if="scope.row.autoCreate === '0'
                          && scope.row.enumerate === '0'
                          && scope.row.fieldType === '字符'"
                        v-model="scope.row.inputType"
                        options="单行文本框,密码文本框,多行文本框"
                        :disabled="scope.row.builtin === '1'"
                      />
                      <ac-select
                        v-else-if="scope.row.fieldType === '日期'"
                        v-model="scope.row.inputType"
                        options="日期单选框,日期多选框"
                        :disabled="scope.row.builtin === '1'"
                      />
                      <ac-select
                        v-else-if="scope.row.fieldType === '大文本'"
                        v-model="scope.row.inputType"
                        options="多行文本框,富文本框"
                        :disabled="scope.row.builtin === '1'"
                      />
                      <el-input v-else :disabled="true" />
                    </template>
                  </el-table-column>
                  <el-table-column
                    v-if="dataModelData.type === '1' || dataModelData.type === '3'"
                    header-align="center"
                    align="center"
                    label="是否必填"
                    :width="80"
                    prop="required"
                  >
                    <template #default="scope">
                      <ac-dict-switch
                        v-model="scope.row.required"
                        dictCode="dictYesNo"
                        :disabled="scope.row.builtin === '1'"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="默认值"
                    :width="100"
                    prop="defaultValue"
                  >
                    <template #header>
                      <span style="margin-right: 5px">默认值</span>
                      <ac-default-value-tips />
                    </template>
                    <template #default="scope">
                      <el-input
                        v-model="scope.row.defaultValue"
                        :disabled="scope.row.builtin === '1'"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="操作"
                    :width="200"
                    fixed="right"
                  >
                    <template #default="scope">
                      <el-button
                        type="primary"
                        @click="editDataField(scope.row)"
                        link
                      >编辑</el-button>
                      <el-button
                        type="success"
                        @click="copyDataField(scope.row)"
                        link
                      >复制</el-button>
                      <el-button
                        v-if="scope.row.fieldType === '联动' && scope.row.relevanceType === '数据模型'"
                        type="success"
                        @click="deriveDataField(scope.row)"
                        link
                      >派生</el-button>
                      <el-button
                        v-if="scope.row.builtin === '0' || !scope.row.builtin"
                        type="danger"
                        @click="deleteDataField(scope.row)"
                        link
                      >删除</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </el-tab-pane>
              <el-tab-pane label="表格设计" name="table" class="fit-box" v-if="dataModelData.id">
                <el-table
                  :show-overflow-tooltip="false"
                  tooltip-effect="light"
                  class="field-table fit-table"
                  width="100%"
                  :data="dataTableList"
                  :border="true"
                  :stripe="false"
                >
                  <el-table-column
                    header-align="center"
                    label="名称"
                    :min-width="120"
                    prop="name"
                  />
                  <el-table-column
                    header-align="center"
                    label="更新时间"
                    :width="160"
                    prop="updateTime"
                  >
                    <template #default="scope">
                      {{date.formatLongDate(scope.row.updateTime)}}
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="操作"
                    :width="200"
                  >
                    <template #default="scope">
                      <el-button
                        type="primary"
                        @click="editDataTable(scope.row)"
                        link
                      >编辑</el-button>
                      <el-button
                        type="success"
                        @click="copyDataTable(scope.row)"
                        link
                      >复制</el-button>
                      <el-button
                        type="info"
                        @click="previewDataTable(scope.row)"
                        link
                      >预览</el-button>
                      <el-button
                        type="danger"
                        @click="deleteDataTable(scope.row)"
                        link
                      >删除</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </el-tab-pane>
              <el-tab-pane label="表单设计" name="form" class="fit-box" v-if="dataModelData.id">
                <el-table
                  :show-overflow-tooltip="false"
                  tooltip-effect="light"
                  class="field-table fit-table"
                  width="100%"
                  :data="dataFormList"
                  :border="true"
                  :stripe="false"
                >
                  <el-table-column
                    header-align="center"
                    label="名称"
                    :min-width="120"
                    prop="name"
                  />
                  <el-table-column
                    header-align="center"
                    label="更新时间"
                    :width="160"
                    prop="updateTime"
                  >
                    <template #default="scope">
                      {{date.formatLongDate(scope.row.updateTime)}}
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="操作"
                    :width="200"
                  >
                    <template #default="scope">
                      <el-button
                        type="primary"
                        @click="editDataForm(scope.row)"
                        link
                      >编辑</el-button>
                      <el-button
                        type="success"
                        @click="copyDataForm(scope.row)"
                        link
                      >复制</el-button>
                      <el-button
                        type="info"
                        @click="previewDataForm(scope.row)"
                        link
                      >预览</el-button>
                      <el-button
                        type="danger"
                        @click="deleteDataForm(scope.row)"
                        link
                      >删除</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </el-tab-pane>
              <el-tab-pane
                v-if="(dataModelData.id && dataModelData.type==='1') || dataModelData.type==='3'"
                label="索引管理"
                name="index"
                class="fit-box"
              >
                <el-table
                  ref="sortTableIndex"
                  v-loading="dataIndexLoading"
                  element-loading-text="数据加载中..."
                  :show-overflow-tooltip="false"
                  class="field-table fit-table edit-table"
                  width="100%"
                  :data="dataIndexList"
                  :border="true"
                  :stripe="false"
                  :row-key="getIndexRowKey"
                >
                  <el-table-column
                    header-align="center"
                    label="索引名称"
                    :min-width="120"
                    prop="indexName"
                  >
                    <template #header>
                      <span style="margin-right: 5px">索引名称</span>
                      <el-tooltip content="索引名称相同时，建联合索引，由排列确定联合索引的顺序。">
                        <ac-icon iconId="018dca8ec9890493be26" />
                      </el-tooltip>
                    </template>
                    <template #default="scope">
                      <el-input v-model="scope.row.indexName" />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="索引字段"
                    :min-width="120"
                    prop="indexFieldId"
                  >
                    <template #default="scope">
                      <ac-select v-model="scope.row.indexFieldId" :options="dataFieldOptions" />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="唯一索引"
                    :width="80"
                    prop="indexUnique"
                  >
                    <template #default="scope">
                      <ac-dict-switch v-model="scope.row.indexUnique" dictCode="dictYesNo" />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="排序方式"
                    :width="200"
                  >
                    <template #default="scope">
                      <ac-radio
                        v-model="scope.row.indexOrdinal"
                        options="升序,降序"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="操作"
                    :width="90"
                    fixed="right"
                  >
                    <template #default="scope">
                      <el-button
                        type="danger"
                        @click="deleteDataIndex(scope.row)"
                        link
                      >删除</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </el-tab-pane>
              <el-tab-pane label="触发器" name="trigger" class="fit-box" v-if="dataModelData.type==='1'">
                <el-row>
                  <el-col :span="8">
                    <el-form-item label="新增前触发脚本" prop="beforeInsertId" label-width="130px">
                      <ac-tree
                        v-model="dataModelData.beforeInsertId"
                        data-url="/system/scriptGroovy/queryTree"
                        type-select="script"
                      />
                    </el-form-item>
                  </el-col>
                  <el-col :span="8">
                    <el-form-item label="新增后触发脚本" prop="afterInsertId" label-width="130px">
                      <ac-tree
                        v-model="dataModelData.afterInsertId"
                        data-url="/system/scriptGroovy/queryTree"
                        type-select="script"
                      />
                    </el-form-item>
                  </el-col>
                </el-row>
                <el-row>
                  <el-col :span="8">
                    <el-form-item label="更新前触发脚本" prop="beforeUpdateId" label-width="130px">
                      <ac-tree
                        v-model="dataModelData.beforeUpdateId"
                        data-url="/system/scriptGroovy/queryTree"
                        type-select="script"
                      />
                    </el-form-item>
                  </el-col>
                  <el-col :span="8">
                    <el-form-item label="更新后触发脚本" prop="afterUpdateId" label-width="130px">
                      <ac-tree
                        v-model="dataModelData.afterUpdateId"
                        data-url="/system/scriptGroovy/queryTree"
                        type-select="script"
                      />
                    </el-form-item>
                  </el-col>
                </el-row>
                <el-row>
                  <el-col :span="8">
                    <el-form-item label="删除前触发脚本" prop="beforeDeleteId" label-width="130px">
                      <ac-tree
                        v-model="dataModelData.beforeDeleteId"
                        data-url="/system/scriptGroovy/queryTree"
                        type-select="script"
                      />
                    </el-form-item>
                  </el-col>
                  <el-col :span="8">
                    <el-form-item label="删除后触发脚本" prop="afterDeleteId" label-width="130px">
                      <ac-tree
                        v-model="dataModelData.afterDeleteId"
                        data-url="/system/scriptGroovy/queryTree"
                        type-select="script"
                      />
                    </el-form-item>
                  </el-col>
                </el-row>
              </el-tab-pane>
            </el-tabs>
            <el-row style="margin-top: 8px;">
              <el-col :span="24" style="text-align: right; margin-right: 10px;;align-content: center;">
                <el-button
                  v-if="tabName === 'field' && !sortableInst && (dataFieldList || []).length > 1"
                  type="primary"
                  @click="sortDataField"
                >开启排序</el-button>
                <el-button
                  v-if="tabName === 'field' && sortableInst"
                  type="info"
                  @click="unSortDataField"
                >关闭排序</el-button>
                <el-button
                  v-if="tabName === 'index' && !sortableIndexInst && (dataIndexList || []).length > 1"
                  type="primary"
                  @click="sortDataIndex"
                >开启排序</el-button>
                <el-button
                  v-if="tabName === 'index' && sortableIndexInst"
                  type="info"
                  @click="unSortDataIndex"
                >关闭排序</el-button>
                <el-button v-if="tabName==='field'" type="success" @click="addSimpleField">添加字段</el-button>
                <el-button v-if="tabName==='field'" type="success" @click="addDataField">添加字段(弹窗)</el-button>
                <el-button v-if="tabName==='table'" type="success" @click="addDataTable">添加表格</el-button>
                <el-button v-if="tabName==='form'" type="success" @click="addDataForm">添加表单</el-button>
                <el-button v-if="tabName==='index'" type="success" @click="addDataIndex">添加索引</el-button>
                <el-button :loading="dataModelLoading" type="primary" @click="submitModelForm">保存</el-button>
              </el-col>
            </el-row>
          </el-form>
        </div>
      </el-main>
    </el-container>
  </div>

  <!--新增编辑目录界面-->
  <el-dialog
    v-model="folderVisible"
    :title="folderTitle"
    width="500px"
    :close-on-click-modal="false"
    destroy-on-close
    draggable
  >
    <el-form
      ref="folderForm"
      label-width="120px"
      label-position="right"
      :model="folderData"
      :rules="folderRules"
    >
      <el-row>
        <el-col :span="24">
          <el-form-item label="目录名称" prop="name">
            <el-input v-model="folderData.name" auto-complete="off"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item label="上级目录" prop="parentId">
            <ac-tree
              v-model="folderData.parentId"
              dataUrl="/system/dataFolder/queryTree"
              :leafSelect="false"
              :disabled="true"
            />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="folderVisible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        :loading="folderLoading"
        @click="submitFolderForm"
      >提交</el-button>
    </template>
  </el-dialog>

  <!--移动编辑目录/数据模型界面-->
  <el-dialog
    v-model="moveVisible"
    :title="moveTitle"
    width="500px"
    :close-on-click-modal="false"
    destroy-on-close
    draggable
  >
    <el-form
      ref="moveForm"
      label-width="120px"
      label-position="right"
      :model="moveData"
    >
      <el-row>
        <el-col :span="24">
          <el-form-item :label="moveData.labelName">
            <ac-input
              v-model="moveData.name"
              :disabled="true"
            />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item label="移动到" prop="folderId">
            <ac-tree
              v-model="moveData.folderId"
              dataUrl="/system/dataFolder/queryTree"
              :leafSelect="false"
            />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="moveVisible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        :loading="moveLoading"
        @click="submitMoveForm"
      >提交</el-button>
    </template>
  </el-dialog>

  <!-- 新增数据模型字段 -->
  <el-dialog
    v-model="fieldVisible"
    title="字段编辑"
    :close-on-click-modal="false"
    destroy-on-close
    fullscreen
    draggable
  >
    <el-form
      ref="fieldForm"
      label-width="140px"
      :model="fieldData"
      :rules="fieldRules"
      style="height: 100%;width: 100%"
    >
      <el-row>
        <el-col :span="8">
          <el-form-item label="字段名称" prop="fieldName">
            <el-input
              v-model="fieldData.fieldName"
              auto-complete="off"
              :disabled="fieldData.builtin === '1'"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="显示名称" prop="showName">
            <el-input
              v-model="fieldData.showName"
              auto-complete="off"
              :disabled="fieldData.builtin === '1'"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="是否必填" prop="required">
            <ac-dict-switch v-model="fieldData.required" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="字段类型" prop="fieldType">
            <ac-select
              v-model="fieldData.fieldType"
              options="字符,整数,小数,日期,时间,图片,视频,附件,联动,派生,大文本"
              @change="changeFieldType(fieldData)"
            />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="fieldData.fieldType === '派生'">
          <el-form-item label="来源字段" prop="sourceFieldId">
            <ac-select
              v-model="fieldData.sourceFieldId"
              :options="dataFieldIdOptions[fieldData.nativeFieldId]"
            />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.fieldType === '联动'"
          :span="8"
        >
          <el-form-item label="联动类型" prop="relevanceType">
            <ac-select
              v-model="fieldData.relevanceType"
              options="数据模型,区划树,单位树,企业树,部门树,人员树,字典树,字典开关,字典单选框,字典下拉框"
            />
          </el-form-item>
        </el-col>
        <el-col
          :span="8"
          v-if="fieldData.fieldType === '联动'
            && fieldData.relevanceType
            && fieldData.relevanceType.startsWith('字典')"
        >
          <el-form-item label="联动字典" prop="relevanceDict">
            <ac-tree
              v-model="fieldData.relevanceDict"
              data-url="/system/dictionary/queryTree"
              :leafSelect="false"
            />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="fieldData.fieldType === '派生'">
          <el-form-item label="原生字段" prop="nativeFieldName">
            <el-input v-model="fieldData.nativeFieldName" :disabled="true" />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="'字符,小数,日期'.indexOf(fieldData.fieldType) >= 0">
          <el-form-item label="字段长度" prop="fieldSize">
            <ac-number
              v-model="fieldData.fieldSize"
              :point="0"
              :disabled="fieldData.builtin === '1'"
            />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.fieldType === '小数'"
          :span="8"
        >
          <el-form-item label="字段精度" prop="fieldPrecision">
            <ac-number
              v-model="fieldData.fieldPrecision"
              :point="0"
              :disabled="fieldData.builtin === '1'"
            />
          </el-form-item>
        </el-col>
        <el-col v-if="fieldData.fieldType === '日期'" :span="8">
          <el-form-item label="日期框类型" prop="inputType">
            <ac-select v-model="fieldData.inputType" options="日期单选框,日期多选框" />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.fieldType === '大文本'"
          :span="8"
        >
          <el-form-item label="文本框类型" prop="inputType">
            <ac-select v-model="fieldData.inputType" options="多行文本框,富文本框" />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.fieldType === '大文本' && fieldData.inputType === '多行文本框'"
          :span="8"
        >
          <el-form-item label="文本框行数" prop="rowLine">
            <ac-number v-model="fieldData.rowLine" :point="0" />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="fieldData.fieldType === '日期'">
          <el-form-item label="格式" prop="format">
            <template #label>
              <span style="margin-right: 5px">格式</span>
              <el-tooltip effect="dark" popper-class="padding-10-15">
                <template #content>
                  <ul class="tips-box">
                    <li>YYYY：4位年份</li>
                    <li>MM：2位月份</li>
                    <li>DD：2位日期</li>
                    <li v-if="fieldData.inputType === '日期单选框'">HH：2位小时</li>
                    <li v-if="fieldData.inputType === '日期单选框'">mm：2位分钟</li>
                    <li v-if="fieldData.inputType === '日期单选框'">ss：2位秒数</li>
                    <li v-if="fieldData.inputType === '日期单选框'">示例：YYYY-MM-DD HH:mm:ss 2025-01-01 23:59:00</li>
                    <li v-if="fieldData.inputType === '日期多选框'">示例：YYYY-MM-DD 2025-01-01</li>
                    <li>默认格式为：YYYY-MM-DD</li>
                  </ul>
                </template>
                <ac-icon iconId="018dca8ec9890493be26" />
              </el-tooltip>
            </template>
            <el-input v-model="fieldData.format" auto-complete="off"></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="'字符,整数,小数,日期,时间,联动'.indexOf(fieldData.fieldType) >= 0">
          <el-form-item label="默认值" prop="defaultValue">
            <template #label>
              <span style="margin-right: 5px">默认值</span>
              <ac-default-value-tips />
            </template>
            <el-input v-model="fieldData.defaultValue" auto-complete="off"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="fieldData.fieldType === '字符'">
        <el-col :span="8">
          <el-form-item label="自动生成" prop="autoCreate">
            <ac-dict-switch v-model="fieldData.autoCreate" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="fieldData.autoCreate === '1'">
          <el-form-item label="自动生成序" prop="autoSequenceId">
            <ac-remote-select
              v-model="fieldData.autoSequenceId"
              dataUrl="/system/sequence/queryPage"
              :option="{id: fieldData.autoSequenceId, name: fieldData.autoSequenceName}"
            />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item v-if="fieldData.autoCreate === '0'" label="是否枚举" prop="enumerate">
            <ac-dict-switch v-model="fieldData.enumerate" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="fieldData.autoCreate === '0' && fieldData.enumerate === '1'">
          <el-form-item label="枚举类型" prop="enumerateType">
            <ac-select
              v-model="fieldData.enumerateType"
              options="开关,单选框,多选框,下拉框,多选下拉框,单位多选,企业多选,部门多选,人员多选,角色多选"
            />
          </el-form-item>
        </el-col>
        <el-col
          :span="8"
          v-if="fieldData.autoCreate === '0'
            && fieldData.enumerate === '1'
            && fieldData.enumerateType !== '单位多选'
            && fieldData.enumerateType !== '企业多选'
            && fieldData.enumerateType !== '部门多选'
            && fieldData.enumerateType !== '人员多选'
            && fieldData.enumerateType !== '角色多选'"
        >
          <el-form-item label="枚举值" prop="enumerateValue">
            <el-input v-model="fieldData.enumerateValue" auto-complete="off"></el-input>
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.autoCreate === '0' && fieldData.enumerate === '0' && fieldData.fieldType === '字符'"
          :span="8"
        >
          <el-form-item label="文本框类型" prop="inputType">
            <ac-select v-model="fieldData.inputType" options="单行文本框,密码文本框,多行文本框" />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.autoCreate === '0'
            && fieldData.enumerate === '0'
            && fieldData.fieldType === '字符'
            && fieldData.inputType === '多行文本框'"
          :span="8"
        >
          <el-form-item label="文本框行数" prop="rowLine">
            <ac-number v-model="fieldData.rowLine" :point="0" />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.autoCreate === '0' && fieldData.enumerate === '0' && fieldData.fieldType === '字符'"
          :span="8"
        >
          <el-form-item label="输入框前置内容" prop="prefixText">
            <ac-input v-model="fieldData.prefixText" />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.autoCreate === '0' && fieldData.enumerate === '0' && fieldData.fieldType === '字符'"
          :span="8"
        >
          <el-form-item label="输入框后置内容" prop="suffixText">
            <ac-input v-model="fieldData.suffixText" />
          </el-form-item>
        </el-col>
        <el-col
          v-if="fieldData.autoCreate === '0' && fieldData.enumerate === '0' && fieldData.fieldType === '字符'"
          :span="8"
        >
          <el-form-item label="删除前后空格" prop="trimBlank">
            <ac-dict-switch v-model="fieldData.trimBlank" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="'整数,小数'.indexOf(fieldData.fieldType) >= 0">
        <el-col :span="8">
          <el-form-item label="最小值" prop="minValue">
            <ac-number v-model="fieldData.minValue" :point="0" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="最大值" prop="maxValue">
            <ac-number v-model="fieldData.maxValue" :point="0" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="'整数,小数'.indexOf(fieldData.fieldType) >= 0">
        <el-col :span="8">
          <el-form-item label="包含最小值" prop="containMinValue">
            <ac-dict-switch v-model="fieldData.containMinValue" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="包含最大值" prop="containMaxValue">
            <ac-dict-switch v-model="fieldData.containMaxValue" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="'整数,小数'.indexOf(fieldData.fieldType) >= 0">
        <el-col :span="8">
          <el-form-item label="输入框前置内容" prop="prefixText">
            <ac-input v-model="fieldData.prefixText" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="输入框后置内容" prop="suffixText">
            <ac-input v-model="fieldData.suffixText" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="fieldData.fieldType === '图片' || fieldData.fieldType === '视频'">
        <el-col :span="8" v-if="fieldData.fieldType === '图片'">
          <el-form-item :label="fieldData.fieldType + '样式'" prop="imageStyle">
            <ac-radio v-model="fieldData.imageStyle" options="长方形,圆形" />
          </el-form-item>
        </el-col>
        <!--
        <el-col :span="8">
          <el-form-item :label="fieldData.fieldType + '数量限制'" prop="imageLimit">
            <ac-number v-model="fieldData.imageLimit" :point="0" />
          </el-form-item>
        </el-col>
        -->
        <el-col :span="8">
          <el-form-item :label="fieldData.fieldType + '宽度'" prop="imageWidth">
            <ac-number v-model="fieldData.imageWidth" :point="0" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item :label="fieldData.fieldType + '高度'" prop="imageHeight">
            <ac-number v-model="fieldData.imageHeight" :point="0" />
          </el-form-item>
        </el-col>
        <el-col :span="8" v-if="fieldData.fieldType === '图片'">
          <el-form-item label="开启手绘" prop="handDraw">
            <ac-dict-switch v-model="fieldData.handDraw" dictCode="dictYesNo" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item :label="fieldData.fieldType + '大小限制(M)'" prop="imageMaxSize">
            <ac-number v-model="fieldData.imageMaxSize" :point="0" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="fieldData.fieldType === '联动' && fieldData.relevanceType === '数据模型'">
        <el-col :span="24">
          <el-form-item label="联动配置">
            <div style="width: 100%;">
              <div >
                <el-button
                  type="success"
                  @click="addFieldRelevance"
                >添加联动层级</el-button>
              </div>
              <div style="padding-top: 5px">
                <el-table
                  ref="sortFieldTable"
                  :show-overflow-tooltip="false"
                  tooltip-effect="light"
                  class="field-table edit-table"
                  width="100%"
                  :data="fieldData.relevanceList"
                  :border="true"
                  :stripe="false"
                >
                  <el-table-column
                    header-align="center"
                    label="数据模型"
                    :min-width="120"
                  >
                    <template #default="scope">
                      <ac-tree
                        v-model="scope.row.dataModelId"
                        data-url="/system/dataModel/queryTree"
                        type-select="model"
                        @change="loadDataFieldOptions(scope.row)"
                      />
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="节点字段"
                    :min-width="120"
                  >
                    <template #default="scope">
                      <ac-select v-model="scope.row.nodeFieldId" :options="scope.row.fieldOptions"/>
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="父节点字段"
                    :min-width="120"
                  >
                    <template #header>
                      <el-tooltip>
                        <template #content>
                          <div>
                            <div>
                              当层级为一层时：如果未录入此字段，则使用下拉框的形式选择联动数据，
                              否则使用树形控件形式选择联动数据。
                            </div>
                            <div>
                              当层级有多层时：第一层不用录入此字段，
                              第二层开始此字段应录入上一层级主键对应的字段，
                              使用树形控件形式选择联动数据
                            </div>
                          </div>
                        </template>
                        <span>
                          <span style="margin-right: 5px">父节点字段</span>
                          <ac-icon iconId="018dca8ec9890493be26" />
                        </span>
                      </el-tooltip>
                    </template>
                    <template #default="scope">
                      <ac-select v-model="scope.row.parentFieldId" :options="scope.row.fieldOptions"/>
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="显示字段"
                    :min-width="120"
                  >
                    <template #default="scope">
                      <ac-select v-model="scope.row.showFieldId" :options="scope.row.fieldOptions"/>
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="排序字段"
                    :min-width="120"
                  >
                    <template #default="scope">
                      <ac-select v-model="scope.row.ordinalFieldId" :options="scope.row.fieldOptions"/>
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="过滤字段"
                    :min-width="120"
                  >
                    <template #default="scope">
                      <ac-select v-model="scope.row.filterFieldId" :options="scope.row.fieldOptions"/>
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    label="过滤值字段"
                    :min-width="120"
                  >
                    <template #default="scope">
                      <ac-select v-model="scope.row.filterValueFieldId" :options="dataFieldOptions"/>
                    </template>
                  </el-table-column>
                  <el-table-column
                    header-align="center"
                    align="center"
                    label="操作"
                    width="80"
                    prop="width"
                  >
                    <template #default="scope">
                      <el-button
                        type="danger"
                        @click="deleteFieldRelevance(scope.row)"
                        link
                      >删除</el-button>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
            </div>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item label="字段描述" prop="description">
            <el-input v-model="fieldData.description" type="textarea" :rows="5" auto-complete="off"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="fieldVisible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        @click="submitFieldForm"
      >确定</el-button>
    </template>
  </el-dialog>

  <!-- 新增/编辑表格 -->
  <el-dialog
    v-model="tableVisible"
    title="编辑表格"
    class="no-padding"
    :close-on-click-modal="false"
    destroy-on-close
    fullscreen
    draggable
  >
    <DataTableEdit ref="tableComp" :options="tableData" @afterSubmit="afterTableSubmit"/>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="tableVisible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        @click="submitTableForm"
      >提交</el-button>
    </template>
  </el-dialog>

  <!-- 新增/编辑表单 -->
  <el-dialog
    v-model="formVisible"
    title="编辑表单"
    class="no-padding"
    :close-on-click-modal="false"
    destroy-on-close
    fullscreen
    draggable
  >
    <DataFormEdit ref="formComp" :options="formData" @afterSubmit="afterFormSubmit"/>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="formVisible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        @click="submitFormForm"
      >提交</el-button>
    </template>
  </el-dialog>

  <!-- 预览 -->
  <el-dialog
    v-model="previewVisible"
    :title="previewTitle"
    :close-on-click-modal="false"
    class="no-padding"
    destroy-on-close
    fullscreen
    draggable
  >
    <div :class="['preview-container', previewPadding ? 'padding20' : 'padding10']">
      <component :is="previewComp" v-bind="previewOptions" />
    </div>
  </el-dialog>
</template>

<script setup>
import { ref, nextTick, watch, onMounted, markRaw } from 'vue';
import { ElMessage, ElMessageBox } from "element-plus";
import Sortable from 'sortablejs';
import api from '@/http/api';
import tool from "@/utils/tool";
import DataTableEdit from "@/admin/codeless/dataTableEdit.vue";
import DataFormEdit from "@/admin/codeless/dataFormEdit.vue";
import Table from "@/codeless/view/table.vue";
import Form from "@/codeless/view/form.vue";
import loading from '@/utils/loading';
import date from "@/utils/date";
import { clearCache } from '@/utils/codeless';

const plusButtons = [
  {type: 'model', name: '新建模型', iconId: '018dc9c3efb74ac607cb', iconColor: '#67C23A'},
  {type: 'folder', name: '新建目录', iconId: '018dc9c3efed6d208a59', iconColor: 'orange', divider: true},
];

const tree = ref();
const filterText = ref('');
const treeLoading = ref(false);
const treeKey = ref('');
const treeData = ref([]);
const treeExpand = ref([]);
const treeProps = ref({
  children: 'children',
  label: function(data) {
    return data.text +
      (data.data.code !== undefined && data.data.code != null
        ? ' [' + data.data.code + ']　' : '　')
  }
});
const treeCheck = ref(false);

const folderTitle = ref('');
const folderVisible = ref(false);
const folderLoading = ref(false);
const folderForm = ref();
const folderData = ref({});
const folderRules = ref({
  name: [{required: true, message: '请输入目录名称', trigger: ['blur', 'change']}],
});

const moveTitle = ref('');
const moveVisible = ref(false);
const moveLoading = ref(false);
const moveForm = ref();
const moveData = ref({});

const fieldFlag = ref(1);
const fieldVisible = ref(false);
const fieldForm = ref();
const fieldData = ref({});
const fieldRules = ref({
  fieldName: [
    {required: true, message: '请输入字段名称', trigger: ['change', 'blur']},
    {max: 50, message: '长度必须小于等于 50 个字符！', trigger: ['change', 'blur']}
  ],
  showName: [
    {required: true, message: '请输入显示名称', trigger: ['change', 'blur']},
    {max: 100, message: '长度必须小于等于 100 个字符！', trigger: ['change', 'blur']}
  ],
  required: [
    {required: true, message: '请选择是否必填', trigger: ['change', 'blur']},
  ],
  fieldType: [
    {required: true, message: '请选择字段类型', trigger: ['change', 'blur']},
  ],
  fieldSize: [
    {required: true, message: '请输入字段长度', trigger: ['change', 'blur']}
  ],
  fieldPrecision: [
    {required: true, message: '请输入字段精度', trigger: ['change', 'blur']}
  ],
  defaultValue: [
    {max: 100, message: '长度必须小于等于 100 个字符！', trigger: ['change', 'blur']}
  ],
  enumerate: [
    {required: true, message: '请输入是否枚举', trigger: ['change', 'blur']},
  ],
  enumerateType: [
    {required: true, message: '请选择枚举选择类型', trigger: ['change', 'blur']},
  ],
  enumerateValue: [
    {required: true, message: '请输入枚举值', trigger: ['change', 'blur']},
    {max: 1000, message: '长度必须小于等于 1000 个字符！', trigger: ['change', 'blur']}
  ],
  autoCreate: [
    {required: true, message: '请选择自动生成', trigger: ['change', 'blur']},
  ],
  autoSequenceId: [
    {required: true, message: '请选择自动生成序', trigger: ['change', 'blur']},
  ],
  relevanceType: [
    {required: true, message: '请选择联动类型', trigger: ['change', 'blur']},
  ],
  relevanceDict: [
    {required: true, message: '请选择联动字典', trigger: ['change', 'blur']},
  ],
  inputType: [
    {required: true, message: '请选择文本框类型', trigger: ['change', 'blur']},
  ],
  trimBlank: [
    {required: true, message: '请选择是否删除前后空格', trigger: ['change', 'blur']},
  ],
  imageStyle: [
    {required: true, message: '请选择样式', trigger: ['change', 'blur']},
  ],
  imageHeight: [
    {required: true, message: '请输入高度', trigger: ['change', 'blur']}
  ],
  imageWidth: [
    {required: true, message: '请输入宽度', trigger: ['change', 'blur']}
  ],
  imageLimit: [
    {required: true, message: '请输入数量限制', trigger: ['change', 'blur']}
  ],
  imageMaxSize: [
    {required: true, message: '请输入大小限制，单位为：M', trigger: ['change', 'blur']}
  ],
  description: [
    {max: 1000, message: '长度必须小于等于 1000 个字符！', trigger: ['change', 'blur']}
  ],
});

const viewLoading = ref(false);

const dataModelShow = ref(false);
const dataModelId = ref('');
const dataModelForm = ref();
const dataModelLoading = ref(false);
const dataModelData = ref({});
const dataModelRules = ref({
  name: [
    {required: true, message: "请输入数据模型名称", trigger: ['blur', 'change']},
    {min: 1, max: 100, message: "数据模型名称长度最多为100个字符", trigger: ['blur', 'change']},
  ],
  type: [
    {required: true, message: "请选择数据模型类型", trigger: ['blur', 'change']},
  ],
});

const tabName = ref('field')
const dataFieldLoading = ref(false);
const dataFieldList = ref([]);
const dataIndexLoading = ref(false);
const dataIndexList = ref([]);
const sortTable = ref();
const sortTableIndex = ref();
const sortableInst = ref();
const sortableIndexInst = ref();
const dataTableList = ref([]);
const dataFormList = ref([]);

const tableComp = ref();
const tableVisible = ref(false);
const tableData = ref({});

const formComp = ref();
const formVisible = ref(false);
const formData = ref({});

const previewVisible = ref(false);
const previewPadding = ref(false);
const previewTitle = ref('');
const previewOptions = ref({});
const previewComp = ref();

const rowFlag = ref(0);

const sortDataField = () => {
  if (sortableInst.value) {
    sortableInst.value.destroy();
  }

  if (sortTable.value) {
    const el = sortTable.value.$el.querySelector(".el-table__body-wrapper tbody");
    sortableInst.value = Sortable.create(el, {
      handle: '.el-table__row',
      onEnd: ({ newIndex, oldIndex}) => {
        const list = tool.deepClone(dataFieldList.value);
        const currRow = list.splice(oldIndex, 1)[0];
        list.splice(newIndex, 0, currRow);
        nextTick(() => {
          dataFieldList.value = list;
        });
      },
      onMove(e) {
        return e.related.className.indexOf('builtin') === -1;
      }
    });
  }
};

const unSortDataField = () => {
  if (sortableInst.value) {
    sortableInst.value.destroy();
  }
  sortableInst.value = null;
};

const sortDataIndex = () => {
  if (sortableIndexInst.value) {
    sortableIndexInst.value.destroy();
  }

  if (sortTableIndex.value) {
    const el = sortTableIndex.value.$el.querySelector(".el-table__body-wrapper tbody");
    sortableIndexInst.value = Sortable.create(el, {
      handle: '.el-table__row',
      onEnd: ({ newIndex, oldIndex}) => {
        const list = tool.deepClone(dataIndexList.value);
        const currRow = list.splice(oldIndex, 1)[0];
        list.splice(newIndex, 0, currRow);
        nextTick(() => {
          dataIndexList.value = list;
        });
      }
    });
  }
};

const unSortDataIndex = () => {
  if (sortableIndexInst.value) {
    sortableIndexInst.value.destroy();
  }
  sortableIndexInst.value = null;
};

const filterNode = (value, data) => {
  if (!value) return true;
  return data.text.indexOf(value) >= 0
    || (data.data.code != null && data.data.code.indexOf(value) >= 0);
};

const currNode = ref();
const nodeClick = (data, treeNode) => {
  unSortDataField();
  dataFieldList.value = [];

  if (currNode.value && currNode.value.id === data.id) {
    treeNode.checked = !treeNode.checked;
  } else {
    treeNode.checked = true;
  }

  if (treeNode.checked) {
    currNode.value = data;
    if (data.type === 'folder') {
      dataModelId.value = '';
      dataModelShow.value = false;
      dataModelLoading.value = false;
    } else {
      dataModelShow.value = true;
      dataModelId.value = data.id;
      loadDataModel(dataModelId.value);
      nextTick(() => {
        dataModelForm.value && dataModelForm.value.clearValidate();
      });
    }
  } else {
    tree.value.setCurrentKey(null);
    dataModelId.value = '';
    dataModelShow.value = false;
    dataModelLoading.value = false;
  }
};

const initDataModel = (data) => {
  dataModelShow.value = true;
  tabName.value = 'field';
  dataModelId.value = data.id || '';
  dataModelForm.value && dataModelForm.value.resetFields();
  dataModelData.value = {folderId: data.folderId || '', type: data.type || '1'};
  dataModelLoading.value = false;
  dataFieldLoading.value = false;
  dataIndexLoading.value = false;
  dataFieldList.value = [];
  dataIndexList.value = [];
  dataFieldOptions.value = [];

  unSortDataField();
  loadDataModel(dataModelId.value);
  nextTick(() => {
    dataModelForm.value && dataModelForm.value.clearValidate();
  });
};

const loadDataModel = (id) => {
  if (!id) {
    currNode.value = null;
    tree.value.setCurrentKey(null);
    return;
  }

  dataModelLoading.value = true;
  api.post('/system/dataModel/queryBy', {id: id}).then(res => {
    dataModelLoading.value = false;
    dataModelData.value = res.data;
    loadDataField(res.data.id);
    loadDataIndex(res.data.id);
    loadDataTable(res.data.id);
    loadDataForm(res.data.id);
  }).catch(() => {
    dataModelLoading.value = false;
  });
};

const loadDataTable = (modelId) => {
  dataTableList.value = [];
  api.post('/system/dataTable/queryList', {modelId: modelId}).then(res => {
    dataTableList.value = res.data;
  });
};

const loadDataForm = (modelId) => {
  dataFormList.value = [];
  api.post('/system/dataForm/queryList', {modelId: modelId}).then(res => {
    dataFormList.value = res.data;
  });
};

const dataFieldOptions = ref([]);
const loadDataField = (modelId) => {
  dataFieldLoading.value = true;
  api.post('/system/dataField/queryList', {modelId: modelId}).then(res => {
    dataFieldList.value = res.data || [];
    dataFieldLoading.value = false;
    dataFieldOptions.value = [];
    dataFieldList.value.forEach(data => {
      dataFieldOptions.value.push({key: data.id, value: data.showName});
    });
  }).catch(() => {
    dataFieldLoading.value = false;
  });
};

const loadDataIndex = (modelId) => {
  dataIndexLoading.value = true;
  api.post('/system/dataIndex/queryList', {modelId: modelId}).then(res => {
    dataIndexList.value = res.data || [];
    dataIndexLoading.value = false;
  }).catch(() => {
    dataIndexLoading.value = false;
  });
};

const loadView = () => {
  viewLoading.value = true;
  api.post('/system/view/queryColumn', {id: dataModelData.value.sourceId}).then(res => {
    viewLoading.value = false;

    (res.data.columnList || []).forEach(column => {
      if (!dataFieldList.value.find(field => field.fieldName === column.columnLabel)) {
        const fieldType = column.dataType || '字符';
        dataFieldList.value.push({
          fieldFlag: ++fieldFlag.value,
          fieldName: column.columnLabel,
          showName: column.columnLabel,
          fieldSize: fieldType === '小数' ? column.columnSize
            : (fieldType === '字符' || fieldType === '整数' ? column.columnSize : null),
          fieldPrecision: fieldType === '小数' ? column.columnPrecision : null,
          fieldType: fieldType,
          inputType: fieldType === '字符' ? '单行文本框' : null,
          trimBlank: fieldType === '字符' ? '1' : null,
        });
      }
    });
  }).catch(e => {
    console.log(e)
    viewLoading.value = false;
  });
};

const changeTable = (data) => {
  dataModelData.value.code = data.id;
  if (data.name && data.name.indexOf(' ') > 0) {
    dataModelData.value.name = data.name.split(' ', 2)[1];
  }
};

const loadTable = () => {
  loadColumn();
  loadIndex();
};

const loadColumn = () => {
  viewLoading.value = true;
  api.post('/system/table/queryColumn', {name: dataModelData.value.sourceId}).then(res => {
    viewLoading.value = false;
    (res.data || []).forEach(column => {
      if (!dataFieldList.value.find(field => field.fieldName === column.name)) {
        const fieldType = column.fieldType || '';
        dataFieldList.value.push({
          fieldFlag: ++fieldFlag.value,
          primaryKey: column.pk + '',
          fieldName: column.name,
          showName: column.comment,
          fieldSize: fieldType === '小数' ? column.precision
            : (fieldType === '字符' || fieldType === '整数' ? column.length : null),
          fieldPrecision: fieldType === '小数' ? column.scale : null,
          fieldType: fieldType,
          inputType: fieldType === '字符' ? '单行文本框' : null,
          trimBlank: fieldType === '字符' ? '1' : null,
        });
        dataFieldOptions.value.push({key: 'temp_' + column.name, value: column.name});
      }
    });
  }).catch(e => {
    console.log(e);
    viewLoading.value = false;
  });
};

const loadIndex = () => {
  api.post('/system/table/queryIndex', {name: dataModelData.value.sourceId}).then(res => {
    dataIndexList.value = [];
    (res.data || []).forEach(index => {
      dataIndexList.value.push(index);
    });
  }).catch(e => {
    console.log(e);
  });
};

const submitModelForm = () => {
  if (!dataFieldList.value || dataFieldList.value.length === 0) {
    ElMessage.error("字段不能为空！")
    return;
  }

  const fieldNames = {};
  for(let field of dataFieldList.value) {
    if (!field.fieldName) {
      ElMessage.error("字段名称不能为空！");
      return;
    }
    if (fieldNames[field.fieldName]) {
      ElMessage.error("【" + field.fieldName + "】字段名称重复！");
      return;
    }
    fieldNames[field.fieldName] = true;
    if (!field.showName) {
      ElMessage.error("【" + field.fieldName + "】显示名称不能为空！");
      return;
    }
    if (field.fieldType === '字符' && !field.fieldSize) {
      ElMessage.error("【" + field.fieldName + "】字段长度不能为空！");
      return;
    }
    if (field.fieldType === '小数' && (!field.fieldSize || (!field.fieldPrecision && field.fieldPrecision !== 0))) {
      ElMessage.error("【" + field.fieldName + "】字段长度/精度不能为空！");
      return;
    }
    if (field.fieldType === '联动' && !field.relevanceType) {
      ElMessage.error("【" + field.fieldName + "】字段联动类型不能为空！");
      return;
    }
  }

  dataModelForm.value && dataModelForm.value.validate((valid) => {
    if (valid) {
      ElMessageBox.confirm("请确认是否提交？", "提示", { type: "info" }).then(() => {
        const data = Object.assign({}, dataModelData.value);
        data.fieldList = tool.deepClone(dataFieldList.value || []);
        data.fieldList.forEach(field => clearDataModelData(field));
        data.indexList = tool.deepClone(dataIndexList.value || []);

        dataModelLoading.value = true;
        api.post('/system/dataModel/save', data).then(res => {
          ElMessage.success(res.message);
          dataModelLoading.value = false;
          dataModelData.value = res.data;
          dataModelId.value = res.data.id;
          loadDataModel(res.data.id);

          treeExpand.value.push(res.data.id || '0');
          treeKey.value = res.data.id || '0';
          loadTreeData();
        }).catch(() => {
          dataModelLoading.value = false;
        });
      }).catch(() => {});
    }
  });
};

const clearDataModelData = (data) => {
  if ('字符,整数,小数,日期,时间,联动'.indexOf(data.fieldType) < 0) {
    data.defaultValue = null;
  }
  if ('字符,日期,小数'.indexOf(data.fieldType) < 0) {
    data.fieldSize = null;
  }
  if ('字符,日期,大文本'.indexOf(data.fieldType) < 0) {
    data.inputType = null;
  }
  if (data.fieldType !== '字符') {
    data.trimBlank = null;
    data.enumerate = null;
  }
  if (data.autoCreate === '1') {
    data.enumerate = null;
    data.enumerateType = null;
    data.enumerateValue = null;
  } else {
    data.autoSequenceId = null;
  }
  if (data.enumerate !== '1') {
    data.enumerateType = null;
    data.enumerateValue = null;
  }
  if (data.fieldType !== '小数') {
    data.fieldPrecision = null;
  }
  if ('整数,小数'.indexOf(data.fieldType) < 0) {
    data.minValue = null;
    data.maxValue = null;
    data.containMinValue = null;
    data.containMaxValue = null;
  }
  if (data.fieldType !== '图片' && data.fieldType !== '视频') {
    data.imageStyle = null;
    data.imageLimit = null;
    data.imageWidth = null;
    data.imageHeight = null;
    data.imageMaxSize = null;
  }
  if (data.fieldType !== '联动') {
    data.relevanceList = [];
  }
  return data;
};

const getFieldRowKey = row => {
  return row.id || row.fieldFlag;
};

const getRowClassName = row => {
  return row.row.builtin === '1' ? 'builtin' : '';
};

const getIndexRowKey = row => {
  return row.id || row.indexFlag;
};

const addDataIndex = () => {
  const data = {
    isNew: false,
    indexFlag: ++fieldFlag.value,
    indexUnique: '0',
    indexOrdinal: '升序',
  };
  dataIndexList.value.push(data);
};

const deleteDataIndex = (data) => {
  const tips = data.fieldName ? ('请确认是否删除【' + data.indexName + '】？') : '请确认是否删除？';
  ElMessageBox.confirm(tips, '提示', {type: 'warning'}).then(() => {
    const index = dataIndexList.value.findIndex(item =>
      (data.id && item.id === data.id) || (item.indexFlag > 0 && item.indexFlag === data.indexFlag));
    dataIndexList.value.splice(index, 1);
  }).catch(() => {});
};

const addSimpleField = () => {
  const data = {
    isNew: false,
    fieldFlag: ++fieldFlag.value,
    required: '0',
    fieldType: '字符',
    fieldSize: 255,
    fieldPrecision: null,
    autoCreate: '0',
    enumerate: '0',
    enumerateType: '下拉框',
    inputType: '单行文本框',
    trimBlank: '1',
    imageStyle: '长方形',
    imageHeight: 200,
    imageWidth: 200,
    imageLimit: 1,
    imageMaxSize: 10,
  };
  const index = dataFieldList.value.findIndex(item => item.ordinal >= 9900);
  if (index > 0) {
    dataFieldList.value.splice(index, 0, data);
  } else {
    dataFieldList.value.push(data);
  }
};

const addDataField = () => {
  fieldData.value = {
    isNew: true,
    fieldFlag: ++fieldFlag.value,
    required: '0',
    fieldType: '字符',
    fieldSize: 255,
    fieldPrecision: 2,
    autoCreate: '0',
    enumerate: '0',
    enumerateType: '下拉框',
    inputType: '单行文本框',
    trimBlank: '1',
    imageStyle: '长方形',
    imageHeight: 200,
    imageWidth: 200,
    imageLimit: 1,
    imageMaxSize: 10,
  };
  fieldVisible.value = true;
};

const changeFieldType = (data) => {
  if (data.fieldType === '字符') {
    data.fieldSize = 255;
    data.fieldPrecision = null;
  } else if (data.fieldType === '小数') {
    data.fieldSize = 18;
    data.fieldPrecision = 2;
  } else if (data.fieldType === '日期') {
    data.fieldSize = 20;
    data.inputType = '日期单选框';
  } else {
    data.fieldSize = null;
    data.fieldPrecision = null;
  }
};

const editDataField = async(field) => {
  fieldData.value = tool.deepClone(field);
  for (let item of fieldData.value.relevanceList || []) {
    await loadDataFieldOptions(item);
  }
  if (fieldData.value.fieldType === '派生' || fieldData.value.nativeFieldId) {
    const nativeField = dataFieldList.value
      .find(item => fieldData.value.nativeFieldId === (item.id || ('temp_' + item.fieldFlag + '')));
    if (nativeField && nativeField.relevanceList && nativeField.relevanceList.length > 0) {
      await loadDataFieldIdOptions(
        nativeField.id || ('temp_' + nativeField.fieldFlag),
        nativeField.relevanceList[nativeField.relevanceList.length - 1]);
    }
    fieldData.value.nativeFieldName = nativeField?.fieldName || '';
  }
  fieldVisible.value = true;
};

const copyDataField = async(field) => {
  const data = tool.deepClone(field || {});
  data.id = null;
  data.isNew = true;
  data.fieldName = (data.fieldName || '') + "_copy";
  data.showName = (data.showName || '') + "_copy";
  data.fieldFlag = ++fieldFlag.value;
  for (let item of data.relevanceList || []) {
    await loadDataFieldOptions(item);
  }
  fieldData.value = data;
  fieldVisible.value = true;
};

const deriveDataField = async(field) => {
  const data = {};
  data.id = null;
  data.isNew = false;
  data.required = '0';
  data.fieldType = '派生';
  data.fieldSize = null;
  data.enumerate = '0';
  data.inputType = '单行文本框';
  data.fieldName = (field.fieldName || '') + "_派生";
  data.showName = (field.showName || '') + "_派生";
  data.nativeFieldId = field.id || ('temp_' + field.fieldFlag + '');
  data.fieldFlag = ++fieldFlag.value;

  const index = dataFieldList.value.findIndex(item =>
    (field.id && item.id === field.id) || (item.fieldFlag > 0 && item.fieldFlag === field.fieldFlag));
  dataFieldList.value.splice(index + 1, 0, data);
};

const deriveDept = async(field) => {
  const find = dataFieldList.value.find(item => item.nativeFieldId && item.nativeFieldId === (field.id || ('temp_' + field.fieldFlag + '')));
  if (find) return;

  const data = {};
  data.id = null;
  data.isNew = false;
  data.required = '0';
  data.fieldType = '联动';
  data.relevanceType = '部门树';
  data.fieldSize = null;
  data.enumerate = '';
  data.inputType = '';
  data.fieldName = (field.fieldName || '') + "_部门";
  data.showName = (field.showName || '') + "_部门";
  data.nativeFieldId = field.id || ('temp_' + field.fieldFlag);
  data.fieldFlag = ++fieldFlag.value;

  const index = dataFieldList.value.findIndex(item =>
    (field.id && item.id === field.id) || (item.fieldFlag > 0 && item.fieldFlag === field.fieldFlag));
  dataFieldList.value.splice(index + 1, 0, data);
};

const deleteDataField = (data) => {
  const tips = data.fieldName ? ('请确认是否删除【' + data.fieldName + '】？') : '请确认是否删除？';
  ElMessageBox.confirm(tips, '提示', {type: 'warning'}).then(() => {
    const index = dataFieldList.value.findIndex(item =>
      (data.id && item.id === data.id) || (item.fieldFlag > 0 && item.fieldFlag === data.fieldFlag));
    dataFieldList.value.splice(index, 1);
    fieldVisible.value = false;
  }).catch(() => {});
};

const submitFieldForm = () => {
  if (fieldData.value.fieldType === '字符' && fieldData.value.fieldSize && fieldData.value.fieldSize > 4000) {
    ElMessage.error("字段【字符长度】的最大值：4000！");
    return;
  } else if (fieldData.value.fieldType === '整数' && fieldData.value.maxValue && fieldData.value.maxValue > 2147483647) {
    ElMessage.error("字段【最大值】的最大值为：2147483647！");
    return;
  }

  fieldForm.value && fieldForm.value.validate((valid) => {
    if (valid) {
      if (dataFieldList.value.findIndex(item => item.id !== fieldData.value.id
          && item.fieldName === fieldData.value.fieldName) >= 0) {
        ElMessage.error("字段名称[" + fieldData.value.fieldName + "]已存在！");
        return;
      }

      if (fieldData.value.isNew === true) {
        fieldData.value.isNew = false;
        const data = fieldData.value;
        const index = dataFieldList.value.findIndex(item => item.ordinal >= 9900);
        if (index > 0) {
          dataFieldList.value.splice(index, 0, data);
        } else {
          dataFieldList.value.push(data);
        }
      } else {
        const data = fieldData.value;
        const index = dataFieldList.value
          .findIndex(item => data.id ? item.id === data.id : item.fieldFlag === data.fieldFlag);
        dataFieldList.value[index] = data;
      }

      if (fieldData.value.fieldType === '联动' && fieldData.value.relevanceType === '人员树') {
        deriveDept(fieldData.value);
      }

      fieldData.value = {};
      fieldVisible.value = false;
    }
  });
};

const addFieldRelevance = () => {
  if (!fieldData.value.relevanceList) {
    fieldData.value.relevanceList = [];
  }

  fieldData.value.relevanceList.push({
    rowFlag: ++rowFlag.value
  });
};

const deleteFieldRelevance = (data) => {
  const index = fieldData.value.relevanceList
    .findIndex(item => data.id ? item.id === data.id : item.rowFlag === data.rowFlag);
  fieldData.value.relevanceList.splice(index, 1);
};

const dataFieldIdOptions = ref({});
const loadDataFieldIdOptions = async(fieldId, data) => {
  if (!data.dataModelId) {
    data.fieldOptions = [];
    return;
  }

  const options = [];
  const res = await api.post('/system/dataField/queryList', {modelId: data.dataModelId});
  (res && res.data || []).forEach(field => {
    options.push({key: field.id, value: field.showName});
  });
  dataFieldIdOptions.value[fieldId] = options;
};

const loadDataFieldOptions = async(data) => {
  if (!data.dataModelId) {
    data.fieldOptions = [];
    return;
  }

  const options = [];
  const res = await api.post('/system/dataField/queryList', {modelId: data.dataModelId});
  (res && res.data || []).forEach(field => {
    options.push({key: field.id, value: field.showName});
  });
  data.fieldOptions = options;
};

const addDataTable = () => {
  if (!dataModelId.value) {
    return;
  }

  tableData.value = {modelId: dataModelId.value};
  tableVisible.value = true;
};

const editDataTable = (data) => {
  tableData.value = {id: data.id, modelId: data.modelId};
  tableVisible.value = true;
};

const copyDataTable = (data) => {
  ElMessageBox.confirm('请确认是否复制？', '提示', {type: 'info'}).then(() => {
    loading.showLoading();
    api.post('/system/dataTable/copy', {id: data.id}).then(res => {
      ElMessage.success(res.message);
      loadDataTable(data.modelId);
      loading.hideLoading();
    }).catch(() => loading.hideLoading());
  }).catch(() => {});
};

const previewDataTable = (data) => {
  clearCache();

  previewVisible.value = true;
  previewPadding.value = false;
  previewTitle.value = "表格预览";
  previewComp.value = markRaw(Table);
  previewOptions.value = {
    dataTableId: data.id,
    dataFieldList: dataFieldList.value,
    autoHeight: '1'
  };
};

const previewDataForm = (data) => {
  clearCache();

  previewVisible.value = true;
  previewPadding.value = true;
  previewTitle.value = "表单预览";
  previewComp.value = markRaw(Form);
  previewOptions.value = {
    dataFormId: data.id,
    fieldList: dataFieldList.value
  };
};

const deleteDataTable = (data) => {
  ElMessageBox.confirm('请确认是否删除【' + data.name + '】？', '提示', {type: 'warning'}).then(() => {
    loading.showLoading();
    api.post('/system/dataTable/delete', {id: data.id}).then(res => {
      ElMessage.success(res.message);
      loadDataTable(data.modelId);
      loading.hideLoading();
    }).catch(() => loading.hideLoading());
  }).catch(() => {});
};

const submitTableForm = () => {
  tableComp.value.submitData();
};

const afterTableSubmit = () => {
  tableVisible.value = false;
  loadDataTable(dataModelId.value);
};

const addDataForm = () => {
  if (!dataModelId.value) {
    return;
  }

  formData.value = {modelId: dataModelId.value};
  formVisible.value = true;
};

const editDataForm = (data) => {
  formData.value = {id: data.id, modelId: data.modelId};
  formVisible.value = true;
};

const copyDataForm = (data) => {
  ElMessageBox.confirm('请确认是否复制？', '提示', {type: 'info'}).then(() => {
    loading.showLoading();
    api.post('/system/dataForm/copy', {id: data.id}).then(res => {
      ElMessage.success(res.message);
      loadDataForm(data.modelId);
      loading.hideLoading();
    }).catch(() => loading.hideLoading());
  });
};

const deleteDataForm = (data) => {
  ElMessageBox.confirm('请确认是否删除【' + data.name + '】？', '提示', {type: 'warning'}).then(() => {
    loading.showLoading();
    api.post('/system/dataForm/delete', {id: data.id}).then(res => {
      ElMessage.success(res.message);
      loadDataForm(data.modelId);
      loading.hideLoading();
    }).catch(() => loading.hideLoading());
  });
};

const submitFormForm = () => {
  formComp.value.submitData();
};

const afterFormSubmit = () => {
  formVisible.value = false;
  loadDataForm(dataModelId.value);
};

const clickPlusItem = (opType, data) => {
  if (opType === 'folder') {
    showFolderDialog('新增', {parentId: data.id, ordinal: 10});
  } else if (opType === 'model') {
    initDataModel({folderId: data.id});
  }
};

const showFolderDialog = (tips, data) => {
  folderTitle.value = tips + '目录';
  folderVisible.value = true;
  folderData.value = Object.assign({}, data);
  folderForm.value && folderForm.value.resetFields();
};

const updateNode = (opType, data) => {
  if (opType === 'folder') {
    showFolderDialog('修改', data);
  } else {
    initDataModel(data);
  }
};

const copyNode = async(opType, data) => {
  if (opType === 'folder' || !data.id) return;

  const res = await api.post('/system/dataField/queryList', {modelId: data.id});
  const fieldList = [];
  const fieldIdMap = {};
  res.data.forEach(field => {
    if (field.builtin && field.builtin === '1') return;

    fieldIdMap[field.id] = ++fieldFlag.value;
    field.fieldFlag = fieldIdMap[field.id];
    delete field.id;

    if (field.relevanceList) {
      field.relevanceList.forEach(relevance => {
        relevance.id = '';
        delete relevance.fieldId;
      });
    }
    fieldList.push(field);
  });

  fieldList.forEach(field => {
    if (field.nativeFieldId) {
      field.nativeFieldId = 'temp_' + fieldIdMap[field.nativeFieldId];
    }
  });
  dataFieldList.value = fieldList || [];

  dataModelShow.value = true;
  tabName.value = 'field';
  dataModelId.value = '';
  dataModelData.value = {folderId: data.folderId || '', type: data.type || '1'};
  dataModelLoading.value = false;
  dataFieldLoading.value = false;
  dataIndexLoading.value = false;
  dataIndexList.value = [];

  unSortDataField();
  await nextTick(() => {
    dataModelForm.value && dataModelForm.value.clearValidate();
  });
};

const moveNode = (opType, data) => {
  moveTitle.value = opType === 'folder' ? '移动目录' : '移动数据模型';
  moveVisible.value = true;
  moveData.value = {
    opType: opType,
    id: data.id,
    name: data.name,
    labelName: opType === 'folder' ? '目录' : '数据模型',
    folderId: opType === 'folder' ? data.parentId : data.folderId
  };
  moveForm.value && moveForm.value.resetFields();
};

const deleteNode = (opType, data) => {
  let url = '/system/dataModel/delete';
  if (opType === 'folder') {
    url = '/system/dataFolder/delete';
  }

  ElMessageBox.confirm('请确认是否删除【' + data.name + '】？', '提示', {type: 'warning'}).then(() => {
    api.post(url, {id: data.id}).then(res => {
      ElMessage.success(res.message);
      dataModelShow.value = false;
      dataModelData.value = {};
      treeExpand.value.push(data.parentId || data.folderId || '0');
      treeKey.value = data.parentId || data.folderId || '0';
      loadTreeData();
    });
  }).catch(() => {
  });
};

const submitFolderForm = () => {
  folderForm.value && folderForm.value.validate((valid) => {
    if (valid) {
      ElMessageBox.confirm('请确认是否提交？', '提示', {type: 'info'}).then(() => {
        folderLoading.value = true;
        api.post('/system/dataFolder/save', folderData.value).then(res => {
          dataModelShow.value = false;
          ElMessage.success(res.message);
          folderVisible.value = false;
          folderLoading.value = false;
          treeExpand.value.push(res.data.id || '0');
          treeKey.value = res.data.id || '0';
          loadTreeData();
        }).catch(() => {
          folderLoading.value = false;
        });
      }).catch(() => {
      });
    }
  });
};

const submitMoveForm = () => {
  moveForm.value && moveForm.value.validate((valid) => {
    if (valid) {
      ElMessageBox.confirm('请确认是否提交？', '提示', {type: 'info'}).then(() => {
        moveLoading.value = true;
        const data = {id: moveData.value.id};
        let url;
        if (moveData.value.opType === 'folder') {
          data.parentId = moveData.value.folderId;
          url = '/system/dataFolder/updateParentId';
        } else {
          data.folderId = moveData.value.folderId;
          url = '/system/dataModel/updateFolder'
        }
        api.post(url, data).then(res => {
          ElMessage.success(res.message);
          moveVisible.value = false;
          moveLoading.value = false;
          treeExpand.value.push(res.data.id || '0');
          treeKey.value = res.data.id || '0';
          loadTreeData();
        }).catch(() => {
          moveLoading.value = false;
        })
      }).catch(() => {
      });
    }
  });
};

const handleExport = () => {
  const nodes = tree.value.getCheckedNodes(false, true);
  if (!nodes || nodes.length === 0) {
    ElMessage.error("请先选择数据模型！");
    return;
  }
  const data = {folderIds: [], modelIds: []};
  nodes.forEach(node => {
    if (node.type === 'folder') {
      data.folderIds.push(node.id);
    } else if (node.type === 'model') {
      data.modelIds.push(node.id);
    }
  });
  api.downloadFile('/system/dataModel/exportData', data).then(res => api.saveFileLocal(res));
};

const handleImport = (file) => {
  api.uploadFile('/system/dataModel/importData', {'file': file.file}).then((res) => {
    ElMessage.success(res.message);
    loadTreeData();
  });
};

const downloadTpl = () => {
  api.downloadFile('/system/dataModel/downloadTpl').then(res => api.saveFileLocal(res));
};

const handleUpload = (file) => {
  return new Promise((resolve, reject) => {
    api.uploadFile('/system/dataModel/uploadXls', {'file': file.file}).then((res) => {
      if (res.code === '2') {
        ElMessage({type: 'error', dangerouslyUseHTMLString: true, message: res.message.replace(/@@@/g, '<br/>')});
        reject();
      } else {
        ElMessage.success(res.message);
        loadTreeData();
        resolve();
      }
    }).catch(() => {
      reject();
    });
  })
};

const loadTreeData = () => {
  treeLoading.value = true;
  api.post('/system/dataModel/queryTree').then(res => {
    const node = tree.value.getCurrentNode();
    if (node !== undefined && node != null) {
      treeExpand.value = [node.id, node.data.parentId, node.data.folderId, '0'];
    } else {
      treeExpand.value = ['0'];
    }
    treeData.value = res.data.children;
    treeLoading.value = false;
    if (treeKey.value) {
      nextTick(() => {
        tree.value.setCurrentKey(treeKey.value);
      });
    }
  }).catch(() => {
    treeLoading.value = false;
  });
};

watch(() => filterText.value, val => {
  tree.value.filter(val);
});

onMounted(() => {
  loadTreeData();
});
</script>

<style  lang="scss">
@import "@/assets/style/codeless.css";
@import "@/assets/style/visual.css";
</style>

<style lang="scss" scoped>
.title {
  display: flex;
  flex-direction: row;
  margin-right: 10px;
  height: 40px;
  align-items: center;

  .title-content {
    flex-grow: 1;
    font-size: 18px;
  }

  .title-button {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    .button-list {
      display: flex;
      flex-direction: row;
      align-items: center;
      .button-item {
        margin: 0 5px 0 5px;
      }
    }
  }

  .title-button .title-button-box {
    height: 30px;
    width: 40px;
    border-radius: 5px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    border: none;
    cursor: pointer;
  }

  .title-button .title-button-box:hover {
    background: #eaeaea;
    border: none;
  }

  .title-button .title-button-box:focus-visible {
    outline: unset;
  }
}

.filter-box {
  margin-right: 10px;
}

.tree :deep(.el-tree-node__content) {
  height: 40px;
}

.page-aside-grow {
  width: 100% !important;

  :deep(.el-tree) {
    display: flex;
    flex-direction: column;
    width: 1px !important;
  }

  :deep(.el-tree-node) {
    display: flex;
    flex-direction: column;
    width: 100% !important;
  }

  :deep(.el-tree-node__content) {
    display: flex;
    flex-grow: 1;
  }
}

.node-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100%;

  .icon {
    display: flex;
    align-items: center;
  }

  .node-label {
    margin-left: 6px;
    flex-grow: 1;
    width: 1px;
    text-overflow: ellipsis;
    overflow: hidden;
    display: flex;

    > span {
      width: 100%;
      text-overflow: ellipsis;
      overflow: hidden;
    }
  }
  .node-button {
    margin-right: 10px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .node-button .node-button-item {
    height: 30px;
    width: 40px;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 5px;
  }
  .node-button .node-button-item:focus-visible {
    outline: unset;
  }
}
.node-item:hover {
  .node-button .node-button-item:hover {
    background: #eaeaea;
  }
}
.preview-container {
  display: flex;
  flex-direction: column;
  background-color: #ffffff;
  flex-grow: 1;
  overflow: auto !important;
}
.preview-container.padding10 {
  padding: 10px;
  width: calc(100% - 20px);
  height: calc(100% - 20px);
}
.preview-container.padding20 {
  padding: 20px;
  width: calc(100% - 40px);
  height: calc(100% - 40px);
}
</style>